package transmit

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"net"
	"time"
)

type Client struct {
	Conn net.Conn
}

type Message struct {
	Id          string `json:"id"`
	From        uint64 `json:"from,optional"`
	To          uint64 `json:"to"`
	Type        uint32 `json:"type"`
	ContentType uint32 `json:"contentType"`
	Time        string `json:"time"`
	Content     string `json:"content"`
}

type TransmitMap struct {
	Users map[string][]uint64 `json:"users,omitempty"`
	Message
}

func (c *Client) Init() (err error) {
	c.Conn, err = net.Dial("tcp", "127.0.0.1:8333")
	return
}

// Producer 客户端发送消息
func (c *Client) Producer(user map[string][]uint64, mes Message) (err error) {
	transmit := TransmitMap{
		Users:   user,
		Message: mes,
	}
	message, _ := json.Marshal(transmit)
	m, _ := Encode(string(message))
	_, err = c.Conn.Write(m)
	if err != nil {
		// 重试三次，一次休眠一秒
		for i := 0; i < 3 && err != nil; i++ {
			time.Sleep(1 * time.Second)
			_, err = c.Conn.Write(m)
		}
	}
	return
}

// Consumer 客户端读取消息并向用户转发
func (c *Client) Consumer() {
	defer c.Conn.Close()
	reader := bufio.NewReader(c.Conn)
	for {
		m, err := Decode(reader)
		if err != nil {
			continue
		}
		transmit := TransmitMap{}
		json.Unmarshal([]byte(m), &transmit)
		// 读到消息后，进行转发
		for _, uIds := range transmit.Users {
			for _, id := range uIds {
				fmt.Println(id, transmit.Message)
			}
		}
	}
}

// Encode 将消息编码
func Encode(message string) ([]byte, error) {
	// 读取消息的长度，转换成int32类型（占4个字节）
	var length = int32(len(message))
	var pkg = new(bytes.Buffer)
	// 写入消息头
	err := binary.Write(pkg, binary.LittleEndian, length)
	if err != nil {
		return nil, err
	}
	// 写入消息实体
	err = binary.Write(pkg, binary.LittleEndian, []byte(message))
	if err != nil {
		return nil, err
	}
	return pkg.Bytes(), nil
}

// Decode 解码消息
func Decode(reader *bufio.Reader) (string, error) {
	// 读取消息的长度
	lengthByte, _ := reader.Peek(4) // 读取前4个字节的数据
	lengthBuff := bytes.NewBuffer(lengthByte)
	var length int32
	err := binary.Read(lengthBuff, binary.LittleEndian, &length)
	if err != nil {
		return "", err
	}
	// Buffered返回缓冲中现有的可读取的字节数。
	if int32(reader.Buffered()) < length+4 {
		return "", err
	}

	// 读取真正的消息数据
	pack := make([]byte, int(4+length))
	_, err = reader.Read(pack)
	if err != nil {
		return "", err
	}
	return string(pack[4:]), nil
}
